﻿/*
 * scadahis.hpp
 *
 *  Created on: 2017年7月10日
 *      Author: work
 */

#ifndef _DM_SCADA_SCADAHIS_HPP_
#define _DM_SCADA_SCADAHIS_HPP_

#include <dm/export.hpp>

#ifndef DM_API_SCADA
#define DM_API_SCADA DM_API_IMPORT
#endif

#include <dm/scada/hisrcd_status.hpp>
#include <dm/scada/hisrcd_discrete.hpp>
#include <dm/scada/hisrcd_measure.hpp>
#include <dm/scada/hisrcd_cumulant.hpp>
#include <dm/scada/hisrcd_action.hpp>

#include <dm/datetime.hpp>
#include <dm/os/db/db.hpp>
#include <dm/auto_array.hpp>
#include <dm/scoped_ptr.hpp>
#include <cstdio>

namespace dm{

namespace os{
class CResultSet;
}

namespace scada{

/**
 * 历史数据接口
 */
class DM_API_SCADA CScadaHis{
	CScadaHis();
	CScadaHis( const CScadaHis& );
public:
	typedef dm::TCAutoArray<CStatus::value_t> status_values_t;
	typedef dm::TCAutoArray<CStatus> statuses_t;
	typedef dm::TCAutoArray<SHisRcdStatus> status_his_t;

	typedef dm::TCAutoArray<CDiscrete::value_t> discrete_values_t;
	typedef dm::TCAutoArray<CDiscrete> discretes_t;
	typedef dm::TCAutoArray<SHisRcdDiscrete> discrete_his_t;

	typedef dm::TCAutoArray<CMeasure::value_t> measure_values_t;
	typedef dm::TCAutoArray<CMeasure> measures_t;
	typedef dm::TCAutoArray<SHisRcdMeasure> measure_his_t;

	typedef dm::TCAutoArray<CCumulant::value_t> cumulant_values_t;
	typedef dm::TCAutoArray<CCumulant> cumulants_t;
	typedef dm::TCAutoArray<SHisRcdCumulant> cumulant_his_t;

	typedef dm::TCAutoArray<CAction::value_t> action_values_t;
	typedef dm::TCAutoArray<CAction> actions_t;
	typedef dm::TCAutoArray<SHisRcdAction> action_his_t;

	typedef dm::CFixdString<64> table_name_t;

	typedef dm::TScopedPtr<dm::os::CResultSet> resultset_p;

	/**
	 * 分表存储类型
	 * 分表存储主要是为了解决大量数据插入操作导致查询被锁的问题
	 */
	enum EMultiTable{
		MtNone,  //!< MtNone 不分表 r_xxx
		MtMinute,//!< MtMinute 按分钟分表存储 r_xxx_yyyymmddhhMM
		Mt2Minutes,
		Mt5Minutes,
		Mt10Minutes,
		Mt20Minutes,
		Mt30Minutes,
		MtHour,  //!< MtHour 按小时分表存储 r_xxx_yyyymmddhh
		Mt2Hours,
		Mt3Hours,
		Mt4Hours,
		Mt6Hours,
		Mt8Hours,
		Mt12Hours,
		MtDay,   //!< MtDay 按天分表存储 r_xxx_yyyymmdd
		MtMonth, //!< MtMonth 按月份分表存储 r_xxx_yyyymm
		MtYear   //!< MtYear 按年度分表存储 r_xxx_yyyy
	};

	static CScadaHis& ins();

	~CScadaHis();

	inline bool isConnected(){
		return m_db->isConnected();
	}

	bool connect();
	void tryUnlock();

	/**
	 * 增加记录
	 * @param rcd
	 */
	void appendStatus( const SHisRcdStatus& rcd );
	void appendDiscrete( const SHisRcdDiscrete& rcd );
	void appendMeasure( const SHisRcdMeasure& rcd );
	void appendCumulant( const SHisRcdCumulant& rcd );
	void appendAction( const SHisRcdAction& rcd );

	bool updateQuery();

	/**
	 * 获取记录的起始时间
	 * @param ts
	 * @return
	 */
	bool getBeginOfStatus( dm::CTimeStamp& ts,const char* name=NULL );
	bool getBeginOfDiscrete( dm::CTimeStamp& ts,const char* name=NULL );
	bool getBeginOfMeasure( dm::CTimeStamp& ts,const char* name=NULL );
	bool getBeginOfCumulant( dm::CTimeStamp& ts,const char* name=NULL );
	bool getBeginOfAction( dm::CTimeStamp& ts,const char* name=NULL );

	/**
	 * 获取记录的结束时间
	 * @param ts
	 * @return
	 */
	bool getEndOfStatus( dm::CTimeStamp& ts,const char* name=NULL );
	bool getEndOfDiscrete( dm::CTimeStamp& ts,const char* name=NULL );
	bool getEndOfMeasure( dm::CTimeStamp& ts,const char* name=NULL );
	bool getEndOfCumulant( dm::CTimeStamp& ts,const char* name=NULL );
	bool getEndOfAction( dm::CTimeStamp& ts,const char* name=NULL );

	/**
	 *  获取第一条记录
	 * @param rcd
	 * @return
	 */
	bool getFirstStatus( SHisRcdStatus& rcd );
	bool getFirstDiscrete( SHisRcdDiscrete& rcd );
	bool getFirstMeasure( SHisRcdMeasure& rcd );
	bool getFirstCumulant( SHisRcdCumulant& rcd );
	bool getFirstAction( SHisRcdAction& rcd );

	/**
	 * 获取最后一条记录
	 * @param rcd
	 * @return
	 */
	bool getLastStatus( SHisRcdStatus& rcd );
	bool getLastDiscrete( SHisRcdDiscrete& rcd );
	bool getLastMeasure( SHisRcdMeasure& rcd );
	bool getLastCumulant( SHisRcdCumulant& rcd );
	bool getLastAction( SHisRcdAction& rcd );

	/**
	 * 获取下一条记录
	 * @param rcd
	 * @return
	 */
	bool getNextStatus( SHisRcdStatus& rcd );
	bool getNextDiscrete( SHisRcdDiscrete& rcd );
	bool getNextMeasure( SHisRcdMeasure& rcd );
	bool getNextCumulant( SHisRcdCumulant& rcd );
	bool getNextAction( SHisRcdAction& rcd );

	/**
	 * 获取前一条记录
	 * @param rcd
	 * @return
	 */
	bool getPreviousStatus( SHisRcdStatus& rcd );
	bool getPreviousDiscrete( SHisRcdDiscrete& rcd );
	bool getPreviousMeasure( SHisRcdMeasure& rcd );
	bool getPreviousCumulant( SHisRcdCumulant& rcd );
	bool getPreviousAction( SHisRcdAction& rcd );

	/**
	 * 获取某时刻记录
	 * @param ts
	 * @param v
	 * @return
	 */
	bool statusAt( const name_t& name,const dm::CTimeStamp& ts,CStatus::value_t& v );
	bool discreteAt( const name_t& name,const dm::CTimeStamp& ts,CDiscrete::value_t& v );
	bool measureAt( const name_t& name,const dm::CTimeStamp& ts,CMeasure::value_t& v );
	bool cumulantAt( const name_t& name,const dm::CTimeStamp& ts,CCumulant::value_t& v );
	bool actionAt( const name_t& name,const dm::CTimeStamp& ts,CAction::value_t& v );

	inline bool statusAt( dm::scada::SHisRcdStatus& rcd  ){
		return statusAt( rcd.name,rcd.ts,rcd.v );
	}

	inline bool discreteAt( dm::scada::SHisRcdDiscrete& rcd ){
		return discreteAt( rcd.name,rcd.ts,rcd.v);
	}

	inline bool measureAt( dm::scada::SHisRcdMeasure& rcd ){
		return measureAt( rcd.name,rcd.ts,rcd.v);
	}

	inline bool cumulantAt( dm::scada::SHisRcdCumulant& rcd ){
		return cumulantAt( rcd.name,rcd.ts,rcd.v);
	}

	inline bool actionAt( dm::scada::SHisRcdAction& rcd ){
		return actionAt( rcd.name,rcd.ts,rcd.v);
	}

	/**
	 * 获取数量
	 * @return
	 */
	int getStatusCount( const char* name=NULL );
	int getDiscreteCount( const char* name=NULL );
	int getMeasureCount( const char* name=NULL );
	int getCumulantCount( const char* name=NULL );
	int getActionCount( const char* name=NULL );

	int getStatusCountBefore( const dm::CTimeStamp& ts,const char* name=NULL );
	int getDiscreteCountBefore( const dm::CTimeStamp& ts,const char* name=NULL );
	int getMeasureCountBefore( const dm::CTimeStamp& ts,const char* name=NULL );
	int getCumulantCountBefore( const dm::CTimeStamp& ts,const char* name=NULL );
	int getActionCountBefore( const dm::CTimeStamp& ts,const char* name=NULL );

	int getStatusCountAfter( const dm::CTimeStamp& ts,const char* name=NULL );
	int getDiscreteCountAfter( const dm::CTimeStamp& ts,const char* name=NULL );
	int getMeasureCountAfter( const dm::CTimeStamp& ts,const char* name=NULL );
	int getCumulantCountAfter( const dm::CTimeStamp& ts,const char* name=NULL );
	int getActionCountAfter( const dm::CTimeStamp& ts,const char* name=NULL );

	int getStatusCount( const dm::CTimeStamp& tsBegin,const dm::CTimeStamp& tsEnd,const char* name=NULL );
	int getDiscreteCount( const dm::CTimeStamp& tsBegin,const dm::CTimeStamp& tsEnd,const char* name=NULL );
	int getMeasureCount( const dm::CTimeStamp& tsBegin,const dm::CTimeStamp& tsEnd,const char* name=NULL );
	int getCumulantCount( const dm::CTimeStamp& tsBegin,const dm::CTimeStamp& tsEnd,const char* name=NULL );
	int getActionCount( const dm::CTimeStamp& tsBegin,const dm::CTimeStamp& tsEnd,const char* name=NULL );

	/**
	 * 清除所有记录
	 */
	void clearStatus( const char* name=NULL );
	void clearDiscrete( const char* name=NULL );
	void clearMeasure( const char* name=NULL );
	void clearCumulant( const char* name=NULL );
	void clearAction( const char* name=NULL );

	/**
	 * 清除以前的记录
	 * @param ts
	 */
	void clearStatusBefore( const dm::CTimeStamp& ts,const char* name=NULL );
	void clearDiscreteBefore( const dm::CTimeStamp& ts,const char* name=NULL );
	void clearMeasureBefore( const dm::CTimeStamp& ts,const char* name=NULL );
	void clearCumulantBefore( const dm::CTimeStamp& ts,const char* name=NULL );
	void clearActionBefore( const dm::CTimeStamp& ts,const char* name=NULL );

	void clearStatusBeforeAndComplement( const dm::CTimeStamp& ts,const char* name=NULL );
	void clearDiscreteBeforeAndComplement( const dm::CTimeStamp& ts,const char* name=NULL );
	void clearMeasureBeforeAndComplement( const dm::CTimeStamp& ts,const char* name=NULL );
	void clearCumulantBeforeAndComplement( const dm::CTimeStamp& ts,const char* name=NULL );
	void clearActionBeforeAndComplement( const dm::CTimeStamp& ts,const char* name=NULL );

	/**
	 * 清除之后的记录
	 * @param ts
	 */
	void clearStatusAfter( const dm::CTimeStamp& ts,const char* name=NULL );
	void clearDiscreteAfter( const dm::CTimeStamp& ts,const char* name=NULL );
	void clearMeasureAfter( const dm::CTimeStamp& ts,const char* name=NULL );
	void clearCumulantAfter( const dm::CTimeStamp& ts,const char* name=NULL );
	void clearActionAfter( const dm::CTimeStamp& ts,const char* name=NULL );

	void clearStatusAfterAndComplement( const dm::CTimeStamp& ts,const char* name=NULL );
	void clearDiscreteAfterAndComplement( const dm::CTimeStamp& ts,const char* name=NULL );
	void clearMeasureAfterAndComplement( const dm::CTimeStamp& ts,const char* name=NULL );
	void clearCumulantAfterAndComplement( const dm::CTimeStamp& ts,const char* name=NULL );
	void clearActionAfterAndComplement( const dm::CTimeStamp& ts,const char* name=NULL );

	inline bool getStatus( status_his_t& d ){
		return getRecordsStatus(d);
	}

	bool getStatus( const name_t& name,status_his_t& d );
	bool getStatusBefore( const dm::CTimeStamp& ts,status_his_t& d );
	bool getStatusBefore( const name_t& name,const dm::CTimeStamp& ts,status_his_t& d );
	bool getStatusAfter( const dm::CTimeStamp& ts,status_his_t& d );
	bool getStatusAfter( const name_t& name,const dm::CTimeStamp& ts,status_his_t& d );
	bool getStatusBetween( const dm::CTimeStamp& s,const dm::CTimeStamp& e,status_his_t& d );
	bool getStatusBetween( const name_t& name,const dm::CTimeStamp& s,const dm::CTimeStamp& e,status_his_t& d );

	inline bool getDiscrete( discrete_his_t& d ){
		return getRecordsDiscrete(d);
	}

	bool getDiscrete( const name_t& name,discrete_his_t& d );

	bool getDiscreteBefore( const dm::CTimeStamp& ts,discrete_his_t& d );
	bool getDiscreteBefore( const name_t& name,const dm::CTimeStamp& ts,discrete_his_t& d );
	bool getDiscreteAfter( const dm::CTimeStamp& ts,discrete_his_t& d );
	bool getDiscreteAfter( const name_t& name,const dm::CTimeStamp& ts,discrete_his_t& d );
	bool getDiscreteBetween( const dm::CTimeStamp& s,const dm::CTimeStamp& e,discrete_his_t& d );
	bool getDiscreteBetween( const name_t& name,const dm::CTimeStamp& s,const dm::CTimeStamp& e,discrete_his_t& d );


	inline bool getMeasure( measure_his_t& d ){
		return getRecordsMeasure(d);
	}

	bool getMeasure( const name_t& name,measure_his_t& d );
	bool getMeasureBefore( const dm::CTimeStamp& ts,measure_his_t& d );
	bool getMeasureBefore( const name_t& name,const dm::CTimeStamp& ts,measure_his_t& d );
	bool getMeasureAfter( const dm::CTimeStamp& ts,measure_his_t& d );
	bool getMeasureAfter( const name_t& name,const dm::CTimeStamp& ts,measure_his_t& d );
	bool getMeasureBetween( const dm::CTimeStamp& s,const dm::CTimeStamp& e,measure_his_t& d );
	bool getMeasureBetween( const name_t& name,const dm::CTimeStamp& s,const dm::CTimeStamp& e,measure_his_t& d );

	inline bool getCumulant( cumulant_his_t& d ){
		return getRecordsCumulant(d);
	}

	bool getCumulant( const name_t& name,cumulant_his_t& d );
	bool getCumulantBefore( const dm::CTimeStamp& ts,cumulant_his_t& d );
	bool getCumulantBefore( const name_t& name,const dm::CTimeStamp& ts,cumulant_his_t& d );
	bool getCumulantAfter( const dm::CTimeStamp& ts,cumulant_his_t& d );
	bool getCumulantAfter( const name_t& name,const dm::CTimeStamp& ts,cumulant_his_t& d );
	bool getCumulantBetween( const dm::CTimeStamp& s,const dm::CTimeStamp& e,cumulant_his_t& d );
	bool getCumulantBetween( const name_t& name,const dm::CTimeStamp& s,const dm::CTimeStamp& e,cumulant_his_t& d );

	inline bool getAction( action_his_t& d ){
		return getRecordsAction(d);
	}

	bool getAction( const name_t& name,action_his_t& d );
	bool getActionBefore( const dm::CTimeStamp& ts,action_his_t& d );
	bool getActionBefore( const name_t& name,const dm::CTimeStamp& ts,action_his_t& d );
	bool getActionAfter( const dm::CTimeStamp& ts,action_his_t& d );
	bool getActionAfter( const name_t& name,const dm::CTimeStamp& ts,action_his_t& d );
	bool getActionBetween( const dm::CTimeStamp& s,const dm::CTimeStamp& e,action_his_t& d );
	bool getActionBetween( const name_t& name,const dm::CTimeStamp& s,const dm::CTimeStamp& e,action_his_t& d );

	static bool string2timeStmp( const char* str,dm::CTimeStamp& ts );
	static void timeStmp2string( const dm::CTimeStamp& ts,char * str/*[24]*/);

	bool ifTable( const char* table );
	void dropTable( const char* table );
	void dropIfTable( const char* table );

	const EMultiTable& multiTableType()const{
		return m_mtType;
	}

	void setMultiTableType( const EMultiTable& type );

	bool refresh( const dm::CTimeStamp& now= dm::CTimeStamp::cur() );

protected:
	void setTableNames( void (*f)(char*,const char*,const dm::CDateTime&) );

	bool append( const table_name_t& tableLast,const table_name_t& tableThis,const table_name_t& tableNext,const name_t& name,const char* value,const dm::CTimeStamp& dts,const dm::CTimeStamp& ots,const int& cause );
	bool append( const char* table,const name_t& name,const char* value,const dm::CTimeStamp& dts,const dm::CTimeStamp& ots,const int& cause );
	bool getTimeStamp( dm::CTimeStamp& ts,const char* table,const char* asc,const char* name=NULL );

	inline bool getBegin( dm::CTimeStamp& ts,const char* table,const char* name=NULL ){
		return getTimeStamp(ts,table,"ASC",name);
	}

	inline bool getEnd( dm::CTimeStamp& ts,const char* table,const char* name=NULL ){
		return getTimeStamp(ts,table,"DESC",name);
	}

	bool getRecord( resultset_p& rs,const char* table,const char* condition );
	bool getRecordStatus( SHisRcdStatus& rcd,const char* condition );
	bool getRecordDiscrete( SHisRcdDiscrete& rcd,const char* condition );
	bool getRecordMeasure( SHisRcdMeasure& rcd,const char* condition );
	bool getRecordCumulant( SHisRcdCumulant& rcd,const char* condition );
	bool getRecordAction( SHisRcdAction& rcd,const char* condition );

	bool getRecords( resultset_p& rs,const char* table,const char* condition=NULL );

	bool getRecordsStatus( status_his_t& d,const char* condition=NULL );
	bool getRecordsDiscrete( discrete_his_t& d,const char* condition=NULL );
	bool getRecordsMeasure( measure_his_t& d,const char* condition=NULL );
	bool getRecordsCumulant( cumulant_his_t& d,const char* condition=NULL );
	bool getRecordsAction( action_his_t& d,const char* condition=NULL );

	void getFirstOrLastCondition( char* condition,bool first=true,const char* name=NULL );
	void getPreviousOrNextCondition( char* condition,const dm::CTimeStamp& ts,bool previous=true,const char* name=NULL );
	void getAtCondition( char* condition,const dm::CTimeStamp& ts,const char* name=NULL );

	int getCountByCondition( const char* table,const char* condition=NULL );
	int getCount( const char* table,const char* name=NULL );

	inline int getCountBefore( const dm::CTimeStamp& ts,const char* table,const char* name=NULL ){
		char condition[128];
		conditionBefore(condition,ts,name);
		return getCountByCondition(table,condition);
	}

	inline int getCountAfter( const dm::CTimeStamp& ts,const char* table,const char* name=NULL ){
		char condition[128];
		conditionAfter(condition,ts,name);
		return getCountByCondition(table,condition);
	}

	inline int getCountNotBefore( const dm::CTimeStamp& ts,const char* table,const char* name=NULL ){
		char condition[128];
		conditionNotBefore(condition,ts,name);
		return getCountByCondition(table,condition);
	}

	inline int getCountNotAfter( const dm::CTimeStamp& ts,const char* table,const char* name=NULL ){
		char condition[128];
		conditionNotAfter(condition,ts,name);
		return getCountByCondition(table,condition);
	}

	inline int getCountBetween( const dm::CTimeStamp& tsBegin,const dm::CTimeStamp& tsEnd,const char* table,const char* name=NULL ){
		char condition[128];
		conditionBetween(condition,tsBegin,tsEnd,name);
		return getCountByCondition(table,condition);
	}

	void clearBefore( const dm::CTimeStamp& ts,const char* table,const char* name=NULL ){
		clear("<",ts,table,name);
	}

	inline void clearAfter( const dm::CTimeStamp& ts,const char* table,const char* name=NULL ){
		clear(">",ts,table,name);
	}

	void clear( const char* type,const dm::CTimeStamp& ts,const char* table,const char* name=NULL );

	inline void clearBeforeAndComplement( const dm::CTimeStamp& ts,const char* table,const char* name=NULL ){
		clearAndComplement("<","<=",ts,table,name);
	}

	inline void clearAfterAndComplement( const dm::CTimeStamp& ts,const char* table=NULL,const char* name=NULL ){
		clearAndComplement(">",">=",ts,table,name);
	}

	void clearAndComplement( const char* type,const char* typeCp,const dm::CTimeStamp& ts,const char* table,const char* name=NULL );

	void clear( const char* table,const char* name=NULL );

	bool createIfStatus( const char* lastMonth,const char* lastMonthShadow,const char* thisMonth,const char* thisMonthShadow,const char* nextMonth,const char* nextMonthShadow );
	bool createIfDiscrete( const char* lastMonth,const char* lastMonthShadow,const char* thisMonth,const char* thisMonthShadow,const char* nextMonth,const char* nextMonthShadow );
	bool createIfMeasure( const char* lastMonth,const char* lastMonthShadow,const char* thisMonth,const char* thisMonthShadow,const char* nextMonth,const char* nextMonthShadow );
	bool createIfCumulant( const char* lastMonth,const char* lastMonthShadow,const char* thisMonth,const char* thisMonthShadow,const char* nextMonth,const char* nextMonthShadow );
	bool createIfAction( const char* lastMonth,const char* lastMonthShadow,const char* thisMonth,const char* thisMonthShadow,const char* nextMonth,const char* nextMonthShadow );

	bool createIfStatus( const char* table );
	bool createIfStatusShadow( const char* table );

	bool createIfDiscrete( const char* table );
	bool createIfDiscreteShadow( const char* table );

	bool createIfMeasure( const char* table );
	bool createIfMeasureShadow( const char* table );

	bool createIfCumulant( const char* table );
	bool createIfCumulantShadow( const char* table );

	bool createIfAction( const char* table );
	bool createIfActionShadow( const char* table );

	bool updateQuery_status();
	bool updateQuery_discrete();
	bool updateQuery_measure();
	bool updateQuery_cumulant();
	bool updateQuery_action();

	static inline void conditionBefore( char* condition,const dm::CTimeStamp& ts,const char* name=NULL ){
		conditionTs(condition,ts,"<",name);
	}

	static inline void conditionAfter( char* condition,const dm::CTimeStamp& ts,const char* name=NULL ){
		conditionTs(condition,ts,">",name);
	}

	static inline void conditionNotBefore( char* condition,const dm::CTimeStamp& ts,const char* name=NULL ){
		conditionTs(condition,ts,">=",name);
	}

	static inline void conditionNotAfter( char* condition,const dm::CTimeStamp& ts,const char* name=NULL ){
		conditionTs(condition,ts,"<=",name);
	}

	static void conditionBetween( char* condition,const dm::CTimeStamp& tsBegin,const dm::CTimeStamp& tsEnd,const char* name=NULL );
	static void conditionTs( char* condition,const dm::CTimeStamp& ts,const char* type,const char* name=NULL );

private:
	dm::TScopedPtr<dm::os::CDb> m_db;

	EMultiTable m_mtType;	// 分表保存类型 默认不分表

	dm::CTimeStamp::s_t m_lastSecs;	// 上时间段起始时刻
	dm::CTimeStamp::s_t m_thisSecs;	// 本时间段起始时刻
	dm::CTimeStamp::s_t m_nextSecs;	// 下时间段起始时刻
	dm::CTimeStamp::s_t m_futureSecs;	// 未来时间段起始时刻

	table_name_t m_tableThisStatus;
	table_name_t m_tableLastStatus;
	table_name_t m_tableNextStatus;

	table_name_t m_tableThisDiscrete;
	table_name_t m_tableLastDiscrete;
	table_name_t m_tableNextDiscrete;

	table_name_t m_tableThisMeasure;
	table_name_t m_tableLastMeasure;
	table_name_t m_tableNextMeasure;

	table_name_t m_tableThisCumulant;
	table_name_t m_tableLastCumulant;
	table_name_t m_tableNextCumulant;

	table_name_t m_tableThisAction;
	table_name_t m_tableLastAction;
	table_name_t m_tableNextAction;
};

}
}

#endif /* INCLUDE_DM_SCADA_SCADAHIS_HPP_ */
